package com.xyy.saas.payment.service.jd;

import com.google.common.collect.Lists;
import com.xyy.saas.payment.dao.model.BankBillJd0028;
import com.xyy.saas.payment.dao.model.PayFinanceRefundPlan;
import com.xyy.saas.payment.rpc.EcOrderRemote;
import com.xyy.saas.payment.service.BankBillJd0028Service;
import com.xyy.saas.payment.service.impl.JDPayServiceImpl;
import com.xyy.saas.payment.trace.AlarmService;
import com.xyy.saas.payment.trace.DingTalkMessage;
import com.xyy.saas.payment.util.DateUtil;
import com.xyy.saas.payment.util.jdpay.FileUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.File;
import java.math.BigDecimal;
import java.text.ParseException;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Component(value = "jDBillServiceImpl0028")
public class JDBillServiceImpl0028 implements JDBillService{
    @Autowired
    private BankBillJd0028Service bankBillJd0028Service;
    @Resource
    private EcOrderRemote ecOrderRemote;
    @Autowired
    private AlarmService alarmService;

    @Override
    public String checkBill(String date) throws Exception {
        boolean isHaveIncompleteBill = false;
        do {
            List<BankBillJd0028> list = bankBillJd0028Service.queryIncompleteBill(DateUtil.parase(date, "yyyy-MM-dd"));
            if (CollectionUtils.isEmpty(list)) {
                break;
            }
            isHaveIncompleteBill = true;
            List<List<BankBillJd0028>> partition = Lists.partition(list, 50);
            for (List<BankBillJd0028> jd0028List : partition) {
                List<String> payNos = new ArrayList<>();
                for (BankBillJd0028 bankBillJd0028 : jd0028List) {
                    String orderType = bankBillJd0028.getOrderType();
                    if (StringUtils.isBlank(orderType)) {
                        continue;
                    }
                    if (orderType.contains("退款")) {
                        payNos.add(bankBillJd0028.getOriOrderNo());
                    } else {
                        payNos.add(bankBillJd0028.getOrderNo());
                    }
                }

                // 调用商城接口获取的填充信息dubbo  key：platMerchantNo、value：返回数据
                // Map<String, PayFinanceRefundPlan> resMap = ecOrderRemote.queryListByPayNoMap(payNos);
                Map<String, PayFinanceRefundPlan> resMap = ecOrderRemote.queryListByPayNoMapV2(payNos);

                // 填充数据
                for (BankBillJd0028 bill : jd0028List) {
                    String payNo = (bill.getOrderType().contains("退款") ? bill.getOriOrderNo() : bill.getOrderNo());
                    PayFinanceRefundPlan result = resMap.get(payNo);
                    if (null != result) {
                        bill.setReceiveId(result.getBusinessReceiverId()); // 商户编码
                        bill.setReceiveName(result.getReceiverName()); // 商户名称
                        bill.setUserName(result.getPayerName()); // 客户名称
                        bill.setYbmOrderNo(result.getBusinessPayNo()); // 药帮忙订单号
                    }
                }
                bankBillJd0028Service.updateBatch(jd0028List);
            }

        } while (true);
        return isHaveIncompleteBill?"缺失商城单据信息":"";
    }
    /**
     * 下载并解析账单
     * shareAccountWater：新分账商户根据交易结算信息生成结算文件（分账子商户）
     */
    @Override
    public void downAndAnalysisBill(String logPrefix, String date) throws Exception {
        if (StringUtils.isBlank(date)) {
            date = DateUtil.format(new Date(), "yyyyMMdd");
        }
        for (String merchantNo : Arrays.asList(JD_PLAT_NO, JD_ACCOUNT_NO, JD_AGGRATE_PLAT_NO, JD_AGGRATE_ACCOUNT_NO)) {
            if (StringUtils.isNotBlank(merchantNo)) {
                // 1、下载账单
                String fileName = date + "shareOrderCreate_" + merchantNo + ".zip";
                String path = "0001/0028";
                download(logPrefix, getOwner(merchantNo), merchantNo, fileName, path, date);
                // 2、解压账单
                FileUtil.unZip(logPrefix, JDPayServiceImpl.getDownPath(date) + File.separator + fileName, JDPayServiceImpl.getDownPath(date));
                // 3、解析账单并入库
                analysisBill(logPrefix, date, getOwner(merchantNo), merchantNo, "0028", fileName);
            }
        }
    }

    /**
     * 删除数据
     * @param billType : 账单类型
     * @param fileName : 文件名称
     * @return 影响行数
     */
    @Override
    public int delete(String logPrefix, String billType, String fileName) {
        return bankBillJd0028Service.delete(BankBillJd0028.builder().fileName(fileName).build());
    }

    /**
     * 批量插入数据
     * @param billType : 账单类型
     * @param records : 账单数据
     * @return 影响行数
     */
    @Override
    public int insertBatch(String logPrefix, String billType, List<Object> records){
        fillParam(logPrefix, billType, records);
        return bankBillJd0028Service.insertBatch(records);
    }

    /**
     * 填充信息：填充 商户编码、商户名称、客户名称、药帮忙订单号
     */
    @Override
    public void fillParam(String logPrefix, String billType, List<Object> records) {
        if (CollectionUtils.isEmpty(records)) {
            return;
        }
        long start = System.currentTimeMillis();
        log.info("{} 填充商城数据开始：账单类型{} 数据量{} ", logPrefix, billType, records.size());

        // 退票记录告警
        Set<String> alarmRefundTNoSet = new HashSet<>();
        // 拼装请求数据
        List<String> payNos = new ArrayList<>();
        for (Object record : records) {
            BankBillJd0028 bill = (BankBillJd0028) record;
            if (bill.getOrderType().contains("退款")) {
                payNos.add(bill.getOriOrderNo());
            } else {
                payNos.add(bill.getOrderNo());
            }

            if ("退票".equals(bill.getOrderType())) {
                alarmRefundTNoSet.add(bill.getOriOrderNo());
            }
        }

        if (CollectionUtils.isNotEmpty(alarmRefundTNoSet)) {
            String alarmRefundTNos = String.join(",", alarmRefundTNoSet);
            DingTalkMessage talkMessage = DingTalkMessage.builder().type("京东支付").method("JDBillServiceImpl0028.fillParam").msg("京东支付含退票记录").param("refundNos: " + alarmRefundTNos).build();
            alarmService.alarm(talkMessage);
        }

        // 调用商城接口获取的填充信息dubbo  key：platMerchantNo、value：返回数据
        // Map<String, PayFinanceRefundPlan> resMap = ecOrderRemote.queryListByPayNoMap(payNos);
        Map<String, PayFinanceRefundPlan> resMap = ecOrderRemote.queryListByPayNoMapV2(payNos);
        log.info("{} 填充商城数据获取商城数据结束：账单类型{} 响应数据量{} ", logPrefix, billType, resMap.size());

        // 填充数据
        for (Object record : records) {
            BankBillJd0028 bill = (BankBillJd0028) record;
            String payNo = (bill.getOrderType().contains("退款") ? bill.getOriOrderNo() : bill.getOrderNo());
            PayFinanceRefundPlan result = resMap.get(payNo);
            if (null != result) {
                bill.setReceiveId(result.getBusinessReceiverId()); // 商户编码
                bill.setReceiveName(result.getReceiverName()); // 商户名称
                bill.setUserName(result.getPayerName()); // 客户名称
                bill.setYbmOrderNo(result.getBusinessPayNo()); // 药帮忙订单号
            }
        }
        log.info("{} 填充商城数据完成：账单类型{}，耗时{}ms", logPrefix, billType, System.currentTimeMillis() - start);
    }

    /**
     * 账单解析
     * @param billType   : 账单类型
     * @param owner      : 一级商户号
     * @param merchantNo : 二级商户号
     * @param fileName   : 文件名称
     * @param billDate   : 账单日期
     * @param line       : 账单数据
     * @return 解析后的实体类
     */
    @Override
    public Object parse(String logPrefix, String billType, String owner, String merchantNo, String fileName, String billDate, String line) {
        BankBillJd0028 bankBillJd0028 = new BankBillJd0028();
        // 基本信息
        bankBillJd0028.setOwner(owner);
        bankBillJd0028.setMerchantNo(merchantNo);
        bankBillJd0028.setFileName(fileName);
        bankBillJd0028.setBillDate(billDate);
        // 账单信息
        String[] cols = line.split(",");
        if (cols.length < 23) {
            log.info("{} [jdPay]账单处理: {}-0028账单，数据行错误，不进行解析：{}", logPrefix, merchantNo, line);
            return null;
        }
        bankBillJd0028.setOrderNo(transCol(cols, 0));
        bankBillJd0028.setBankOrderNo(transCol(cols, 1));
        bankBillJd0028.setOrderAmount(StringUtils.isEmpty(transCol(cols, 2)) ? new BigDecimal("0") : new BigDecimal(transCol(cols, 2)));
        bankBillJd0028.setBusinessType(transCol(cols, 3));
        bankBillJd0028.setOrderType(transCol(cols, 4));
        bankBillJd0028.setOrderStatus(transCol(cols, 5));
        bankBillJd0028.setRefundAmount(StringUtils.isEmpty(transCol(cols, 6)) ? new BigDecimal("0") : new BigDecimal(transCol(cols, 6)));
        bankBillJd0028.setSettleStatus(transCol(cols, 7));
        bankBillJd0028.setTradeTime(transCol(cols, 8));
        bankBillJd0028.setDealTime(transCol(cols, 9));
        bankBillJd0028.setOriOrderNo(transCol(cols, 10));
        bankBillJd0028.setFee(StringUtils.isEmpty(transCol(cols, 11)) ? new BigDecimal("0") : new BigDecimal(transCol(cols, 11)));
        bankBillJd0028.setAccountName(transCol(cols, 12));
        bankBillJd0028.setBankName(transCol(cols, 13));
        bankBillJd0028.setBusinessOrderNo(transCol(cols, 14));
        bankBillJd0028.setTradeNo(transCol(cols, 15));
        bankBillJd0028.setPlatMerchantNo(transCol(cols, 16));
        bankBillJd0028.setPlatMerchant(transCol(cols, 17));
        bankBillJd0028.setPlatMerchantName(transCol(cols, 18));
        bankBillJd0028.setPlatInTransitMerchant(transCol(cols, 19));
        bankBillJd0028.setSubMerchant(transCol(cols, 20));
        bankBillJd0028.setCommissionMsg(transCol(cols, 21).replace("，", ","));
        bankBillJd0028.setMarketingMsg(transCol(cols, 22).replace("，", ","));
        bankBillJd0028.setCommissionAmount(transCol(cols, 23));
        bankBillJd0028.setRemark(transCol(cols, 24));
        return bankBillJd0028;
    }

}
